﻿

namespace GameServer
{

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Text;
    using System.Threading;
    using Nonoba.GameLibrary;
    using GameServer.ShootingGame;
    using GameServer.ShootingGame.WeaponsClasses;
    using GameServer.ShotInTheDark;
    using GameServer.ShootingGame.RenderableClasses;
    using System.Reflection;
    using GameServer.Common;
    public delegate GamePlay GamePlayDelegate();
    public delegate void SingleParameteredDelegate_GameObject(GameObject g);
    public delegate void SingleParameteredDelegate_PlayerObject(PlayerObject g);

    public class Player : NonobaGameUser { }
    public class ShooterServer : NonobaGame<Player>
    {

        public const string MSG_MY_USER_DATA = "my_user_data";
        public const string MSG_PLAYERS_IN_GAME = "players_in_game";
        public const string MSG_JOIN_GAME = "join_Game";
        public const string MSG_MOUSE_COORDS = "mouse_coords";
        public const string MSG_PLAYER_POSITION = "player_position";
        public const string MSG_KEYSTATES = "keystates";
        public const string MSG_THRUST = "thrust";
        public const string MSG_PICKED_UP_WEAPON = "pickup_weapon";
        public const string MSG_SPAWN_WEAPON = "spawn_weapon";
        public const string MSG_WEAPON_LOCATIONS = "weapon_locations";
        public const string MSG_EXPIRED_PLAYER = "expired_player";
        public const string MSG_RESPAWN = "respawn";

        public const string MSG_ORDINANCE_DATA = "ordinance_data";
        public const string MSG_PLAYER_DATA = "player_data";
        public const string MSG_PICKUP_DATA = "pickup_data";

        public GamePlay gamePlay;

        private TimedParameteredDelegateList timedExecutionList;

        public ShooterServer()
        {
            timedExecutionList = new TimedParameteredDelegateList();
        }

        public void testFunction(string str)
        {
            Console.WriteLine(str);
        }

        public override void GameStarted()
        {
            gamePlay = new GamePlay(this);
        }



        public override void UserJoined(Player user)
        {
            Console.WriteLine(MSG_MY_USER_DATA, user.UserId, user.Username);
            gamePlay.PlayerJoined(user.UserId, user.Username);
            //This doesn't work here!!?
            user.Send("stop", user.UserId, user.Username);
        }

        public override void UserLeft(Player user)
        {
        }

        public override void GotMessage(Player user, Message message)
        {
            switch (message.Type)
            {
                case MSG_MY_USER_DATA:
                    {
                        Message userData = new Message(MSG_MY_USER_DATA, user.UserId, user.Username);
                        foreach (PlayerObject playerObj in gamePlay.PlayerList)
                        {
                            if (playerObj.id == user.UserId)
                            {
                                playerObj.width = message.GetDouble(0);
                                playerObj.height = message.GetDouble(1);
                                userData.Add(playerObj.xPosition);
                                userData.Add(playerObj.yPosition);
                                Console.WriteLine(userData.Count + " " + userData[2] + " " + userData[3]);
                                break;
                            }
                        }
                        Message usersList = new Message(MSG_PLAYERS_IN_GAME);
                        for (int i = 0; i < Users.Length; i++)
                        {
                            if (Users[i] != user)
                                usersList.Add(Users[i].UserId, Users[i].Username);
                        }
                        Message pickupListMessage = new Message(MSG_WEAPON_LOCATIONS);
                        for (int i = 0; i < gamePlay.PickupList.Count; i++)
                        {
                            pickupListMessage.Add(gamePlay.PickupList[i].id, (int)((gamePlay.PickupList[i].pickupItem as Weapon).type), gamePlay.PickupList[i].xPosition, gamePlay.PickupList[i].yPosition);
                        }
                        user.Send(userData, usersList, pickupListMessage);
                        Broadcast(MSG_JOIN_GAME, user.UserId, user.Username);
                        break;
                    }
                case MSG_MOUSE_COORDS:
                    {
                        foreach (PlayerObject playerObj in gamePlay.PlayerList)
                        {
                            if (playerObj.id == user.UserId)
                            {
                                playerObj.MouseX = message.GetDouble(0);
                                playerObj.MouseY = message.GetDouble(1);
                                break;
                            }
                        }
                        Broadcast(MSG_MOUSE_COORDS, user.UserId, user.Username, message.GetDouble(0), message.GetDouble(1));
                        break;
                    }
                case MSG_PLAYER_POSITION:
                    {
                        foreach (PlayerObject playerObj in gamePlay.PlayerList)
                        {
                            if (playerObj.id == user.UserId)
                            {
                                playerObj.xPosition = message.GetDouble(0);
                                playerObj.yPosition = message.GetDouble(1);
                                break;
                            }
                        }
                        break;
                    }
                case MSG_KEYSTATES:
                    {
                        KeyStates keystates;
                        foreach (PlayerObject playerObj in gamePlay.PlayerList)
                        {
                            if (playerObj.id == user.UserId)
                            {
                                keystates = playerObj.keyStates;
                                keystates.up = message.GetBoolean(0);
                                keystates.down = message.GetBoolean(1);
                                keystates.left = message.GetBoolean(2);
                                keystates.right = message.GetBoolean(3);
                                keystates.mouseLeft_Down = message.GetBoolean(4);
                                playerObj.MouseX = message.GetDouble(5) + (playerObj.xPosition - 400);
                                playerObj.MouseY = message.GetDouble(6) + (playerObj.yPosition - 300);
                                Broadcast(MSG_KEYSTATES, user.UserId, user.Username, message.GetBoolean(0), message.GetBoolean(1), message.GetBoolean(2), message.GetBoolean(3), message.GetBoolean(4), playerObj.MouseX, playerObj.MouseY);
                                break;
                            }
                        }
                        break;
                    }

                case MSG_EXPIRED_PLAYER:
                    {
                        Console.WriteLine("died " + message.GetInt(0));
                        foreach (PlayerObject playerObj in gamePlay.PlayerList)
                        {
                            Console.WriteLine("id " + playerObj.id + "\n");
                            if (playerObj.id == message.GetInt(0))
                            {
                                Console.WriteLine(playerObj.IsExpired);
                                if (!playerObj.IsExpired)
                                {
                                    playerObj.IsExpired = true;
                                    timedExecutionList.Add(new ParameteredDelegateData(new SingleParameteredDelegate_PlayerObject(gamePlay.SpawnPlayer), new object[] { playerObj }), Config.TIME_RESPAWN);
                                    Console.WriteLine(message.GetInt(0) + " " + playerObj.id);
                                    BroadCastExcluding(new int[] { user.UserId }, MSG_EXPIRED_PLAYER, message.GetInt(0));
                                }
                                break;
                            }
                            Console.WriteLine("|");
                            
                        }
                        Console.WriteLine("\n");
                        break;
                    }
                case MSG_THRUST:
                    {
                        Broadcast(MSG_THRUST, user.UserId, user.Username, message.GetInt(0), message.GetInt(1), message.GetInt(2), message.GetInt(3), message.GetInt(4));
                        break;
                    }
                case MSG_PICKED_UP_WEAPON:
                    {
                        gamePlay.GenerateWeaponPickup(message.GetInt(0));
                        break;
                    }
            }
        }

        public void MultiCast(int[] userIds, Message message)
        {
            for (int i = 0; i < userIds.Length; i++)
            {
                foreach (Player user in Users)
                {
                    if (user.UserId == userIds[i])
                        user.Send(message);
                }
            }
        }

        public void MultiCast(int[] userIds, params Message[] message)
        {
            for (int i = 0; i < userIds.Length; i++)
            {
                foreach (Player user in Users)
                {
                    if (user.UserId == userIds[i])
                        user.Send(message);
                }
            }
        }


        /// <summary>
        /// Sends the message to all users except the specified user ids.
        /// </summary>
        /// <param name="excludedUserIds">Array of userIds to exclude from the broadcast</param>
        /// <param name="type"></param>
        /// <param name="parameters"></param>
        public void BroadCastExcluding(int[] excludedUserIds, string type, params object[] parameters)
        {
            bool isExcluded;
            foreach (Player user in Users)
            {
                isExcluded = false;
                for (int i = 0; i < excludedUserIds.Length; i++)
                {
                    if (user.UserId == excludedUserIds[i])
                    {
                        isExcluded = true;
                        break;
                    }
                }
                if (!isExcluded)
                    user.Send(type, parameters);
            }

        }

        /// <summary>
        /// Sends the message to all users except the specified user ids.
        /// </summary>
        /// <param name="excludedUserIds">Array of userIds to exclude from the broadcast</param>
        /// <param name="messages"></param>
        public void BroadCastExcluding(int[] excludedUserIds, params Message[] messages)
        {
            bool isExcluded;
            foreach (Player user in Users)
            {
                isExcluded = false;
                for (int i = 0; i < excludedUserIds.Length; i++)
                {
                    if (user.UserId == excludedUserIds[i])
                    {
                        isExcluded = true;
                        break;
                    }
                }
                if (!isExcluded)
                    user.Send(messages);
            }

        }


        public TimedParameteredDelegateList TimedExecutionList
        {
            get { return timedExecutionList; }
        }
    }
}